# encoding:utf8
import os
import sys
import shutil
import json
from ccpm.collogger import Log
from ccpm.pmbase import PluginBase, PmUtil
from argparse import ArgumentParser
from mgamedev.py_lib.decorator import singleton
from ccpm.conffac import PackConf, PluginConf, GConf
from ccpm.glan import Lan
from mgamedev.py_lib.luabase import LuabaseTool
from ccpm.net import NetUtil
import copy
from ccpm.constants import Constant, Ptype
import uuid
import zipfile
import operator
import hashlib
import oss2
from ccpm.model.modelusr import ModelUsr
from ccpm.auth.gitee_auth import GiteeLogin
from ccpm.constants import Constant
from ccpm.hookfac import HookFunc


'''
packcfg.json 
{
    --must(temp_pack.json)
    "name": "template_package",
    "ver": "v0.1.0",
    "desc": "test package",
    "license": "isc",
    "dependencies": []

    --optional
    "entry": "init.lua",--是否有入口
    "dev-tool":"cocos_simulator"
}
reslist.json 
[
    文件详情列表
]
'''


def write_2zip(zippath, tarfile):
    filelist = []
    if os.path.isfile(zippath):
        filelist.append(zippath)
    else:
        for dirpath, dirnames, filenames in os.walk(zippath):
            for filename in filenames:
                filelist.append(os.path.join(dirpath, filename))
    f = zipfile.ZipFile(tarfile, 'w', zipfile.ZIP_DEFLATED)
    for tar in filelist:
        arcname = tar[len(zippath):]
        f.write(tar, arcname)
    f.close()


def process_stdout(nsize, tsize):
    percent = float(nsize) / float(tsize)
    percent = round(percent*100, 2) if percent <= 100.0 else 100.0
    sys.stdout.write(
        ("Process-->>(%dbyte/%dbyte)(%0.2f%%) \r") % (int(nsize),
                                                      int(tsize), percent))
    sys.stdout.flush()
    if nsize >= tsize:
        sys.stdout.write("\n")


@singleton
class PublishPlugin(PluginBase):

    PLUGIN_INFO = dict(
        name="publish",
        help="publish the package by package"
    )

    IS_CHKLOCAL_USR = True

    def __init__(self):
        super().__init__(self.PLUGIN_INFO)
        self._packconf = None

    def __chk_format():
        # todo: Chk the conf fmt forbiden upload wrong global-config
        return True

    def parser_config(self, argparser):
        super().parser_config(argparser)
        argparser.add_argument("-a", dest="isxlhook",
                               help="compatibility the  xl-work,change hook-func dir",
                               default=False)
        argparser.add_argument("-p", dest="hookname",
                               help="the hookfunc file belong path name",
                               default=False)

    def __chk_require_entry(self):
        if ("entry" not in self._packconf):
            return
        npath = os.getcwd()
        packf = os.path.join(npath, self._packconf["entry"])
        if not os.path.isfile(packf):
            self.err_break(
                Lan.p(self.name, "ERR_REQUIRE_ENTRYF", packf))

    def __chk_publish_enable(self):
        self.__chk_libname_only()
        self.__chk_same_giteeusr()

    def __chk_same_giteeusr(self):
        # todo
        return True

    def __chk_libname_only(self):
        name = self._packconf["name"]
        pinfo_list = NetUtil.plugin_exist_chk(name)
        if isinstance(pinfo_list, list):
            for pinfo in pinfo_list:
                if pinfo["ver"] == self._packconf["ver"]:
                    self.err_break(
                        Lan.p(self.name, "ERR_REMOTE_PLUGINEXIST", name,
                              str(pinfo["ver"])))

    def __zip_resources(self):
        zfname = "%s@%s.zip" % (self._packconf["name"], self._packconf["ver"])
        tmpdirname = str(uuid.uuid1())
        tmppath = os.path.join(os.getcwd(), tmpdirname)
        # pack-ignore
        ignore_filter = None
        ignore_list = [".*", "*.zip"]
        if "packignore" in self._packconf:
            for ignobj in self._packconf["packignore"]:
                ignore_list.append(ignobj)
        ignore_filter = shutil.ignore_patterns(*ignore_list)
        shutil.copytree(os.getcwd(), tmppath, ignore=ignore_filter)

        """ HOOK[publish_pre_zip] """
        if self.params_var("is_hookfunc"):
            if self.hookdir:
                path_hook = os.path.join(Constant.HOOKS_PATH, self.hookdir)
                HookFunc().set_hookpath(path_hook)
            HookFunc().hook_exe(self.is_ignorehook(), "publish_pre_zip",
                                tmppath)

        write_2zip(tmppath, zfname)

        self.append_rm_tmp(tmppath)
        return zfname

    def __chk_usr(self):
        self.logger.info(Lan.p(self.name, "RUN_STEP4"))
        if not self.IS_CHKLOCAL_USR:
            return True
        if not PmUtil.chk_usr_enable():
            self.err_break(Lan.p(self.name, "ERR_GET_GITEEUSR_FAILED"))

    def upload_by_oss2(self, fzip):
        ACCESS_KEY = PluginConf().get("_oss").oss2_accesskey
        ACCCESS_KEY_SECRET = PluginConf().get("_oss").oss2_secure
        REMOTE_PATH = PluginConf().get("_oss").oss_path
        OSS_DOWNLOAD_URL = PluginConf().get("_oss").oss_download_url
        OSS_DOWNLOAD_BUCKET = PluginConf().get("_oss").oss_bucket
        # 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号。
        auth = oss2.Auth(ACCESS_KEY, ACCCESS_KEY_SECRET)
        oss2.logger.setLevel(30)  # not import logging module
        # Endpoint以杭州为例，其它Region请按实际情况填写。
        bucket = oss2.Bucket(
            auth, OSS_DOWNLOAD_URL, OSS_DOWNLOAD_BUCKET)

        ret = NetUtil.oss2_upload(
            bucket, os.path.join(REMOTE_PATH, fzip), fzip)
        return ret

    def upload_by_sftp(self, fzip):
        # uploading
        pwd = PluginConf().get("_sftp").pwd
        remote_path = PluginConf().get("_sftp").remote_path
        remote_host = PluginConf().get("_sftp").remote_host
        ret = NetUtil.sftp_upload(pwd, os.path.abspath(
            fzip), remote_host, remote_path)
        NetUtil.unzip_remotezip(os.path.join(remote_path, fzip))
        return ret

    def run(self, argpars):
        super().run(argpars)
        is_xlhook = argpars.isxlhook
        hookdir = argpars.hookname
        if is_xlhook:
            hookdir = "xlhook"
        is_upload_by_oss2 = GConf().get("is_oss2")
        self.isxlhook = is_xlhook
        self.hookdir = hookdir

        self.logger.info(Lan.p(self.name, "RUN_STEP1"))

        # fresh timestamp first
        os.system('''sh -c "find ./ * -exec touch {} \;">>/tmp/a.log''')

        # chk local-user
        self.__chk_usr()
        # chk conf-file
        (issuc, packconf) = PmUtil.is_package_projpath(os.getcwd())
        if (not issuc):
            self.err_break(Lan.p(self.name, "ERR_REUQIREFMT"))
        else:
            issuc = PmUtil.is_packcfg_fmtright(packconf)
            if not issuc:
                self.err_break(Lan.p(self.name, "ERR_KEYFMT_DISABLE"))
        self._packconf = packconf
        # chk entry and plugin-info
        self.__chk_require_entry()
        self.__chk_publish_enable()
        self.logger.info(Lan.p(self.name, "RUN_STEP3"))
        # start pack
        fzip = self.__zip_resources()
        fzip_size = round((os.path.getsize(fzip) / float(1024)), 2)
        fzip_md5 = PmUtil.get_file_md5(fzip)
        # upload
        ret = False
        if is_upload_by_oss2:
            ret = self.upload_by_oss2(fzip)
        else:
            ret = self.upload_by_sftp(fzip)

        if ret:
            dbinfo = copy
            self._packconf["contsize"] = fzip_size
            self._packconf["md5"] = fzip_md5
            self._packconf["ptype"] = Ptype.get_ptype(self._packconf["pdesc"])
            self._packconf["gitee_usr"] = str(ModelUsr().get_name())
            self.logger.info("upload info:%s", str(self._packconf))
            (ret, err) = NetUtil.add_plugin_db(self._packconf)
            if not ret:
                self.err_break(Lan.p(self.name, "ERR_INSERT_DB_FAILED"))
        else:
            self.err_break(Lan.p(self.name, "ERR_UPLOAD_FAILED"))
        # os.remove(os.path.abspath(fzip))
        self.append_rm_tmp(fzip)
        self.rm_temp()


__all__ = [
    "PublishPlugin"
]
